#ifndef __TDP2_GLRENDERDEVICE_HPP__
#define __TDP2_GLRENDERDEVICE_HPP__

#include "tdp2_renderdevice.hpp"
#include "tdp2_glfunctions.hpp"
#include "../../rdx/src/rdx/rdx_objectmanagement.hpp"

namespace TDP
{
	namespace Rendering
	{
		struct IGLInitializer
		{
			virtual void *GetProcAddress(const char *str) const = 0;
		};

		enum GLTextureTarget
		{
			GLTT_Texture2D,
			GLTT_TextureRect,
			GLTT_Texture3D,
			GLTT_TextureCube,

			GLTT_Count,
		};

		enum GLPixelStoreSetting
		{
			GLPSS_PackAlignment,
			GLPSS_UnpackAlignment,

			GLPSS_Count,
		};

		struct GLTexture
		{
			GLenum iformat;
			GLenum exchannels;
			GLenum exformat;
			GLenum texID;
			GLTextureTarget target;
			const GLenum *sides;
			unsigned int numSides;
			unsigned int bpp;
			UInt32 width, height, depth;
			bool threeD, compressed;
		};

		struct GLShader
		{
			GLint shaderID;
			GLhandleARB shaderType;
			bool isCompiled;
			bool isGLSL;
		};

		struct GLTextureBinding
		{
			GLenum target;
			GLenum binding;
			GLuint value;
		};

		struct GLPixelStoreBinding
		{
			GLenum pname;
			GLint value;
		};

		class GLState
		{
			GLFunctions *_gl;
			GLTextureBinding _textureBinding[GLTT_Count];
			GLPixelStoreBinding _pixelStoreBindings[GLPSS_Count];

		public:
			GLenum TextureTarget(GLTextureTarget target) const;
			void BindTexture(GLTextureTarget target, GLuint name);
			void PixelStore(GLPixelStoreSetting pss, GLint value);
			void Initialize(GLFunctions *gl);

			void GetCurrent();
		};

		class GLRenderDevice : public IRenderDevice
		{
			bool _startedOK;
			GLFunctions _gl;
			GLState _initialState;
			GLState _state;
			RDX::ObjectManagement::Allocator _alloc;
		public:
			GLRenderDevice(const ::RDX::ObjectManagement::Allocator &alloc, const IGLInitializer *initializer, const char **blame);
			~GLRenderDevice();

			bool CreateTexture(Resources::TextureSpec::TextureFormat tf, Resources::TextureSpec::TextureLayout tl, UInt32 numMipMaps,
				UInt32 width, UInt32 height, UInt32 depth, UInt32 flags, RenderTextureHandle *outRTH);
			void UploadTextureRows(RenderTextureHandle rth, UInt32 level, UInt32 side, UInt32 y, UInt32 layer, UInt32 numRows, const void *data, LargeUInt numBytes);
			void UploadTextureSubRow(RenderTextureHandle rth, UInt32 level, UInt32 side, UInt32 x, UInt32 y, UInt32 layer, UInt32 width, const void *data, LargeUInt numBytes);
			void SetTextureMaxLOD(RenderTextureHandle rth, UInt32 level);
			void SetTextureMinLOD(RenderTextureHandle rth, UInt32 level);
			bool DestroyTexture(RenderTextureHandle rth);

			bool CreateShader(Resources::ShaderSpec::ShaderType shaderType, const void *data, LargeUInt sizeBytes, RenderShaderHandle *outRSH);
			void DestroyShader(RenderShaderHandle rsh);

			bool StartedOK() const;
		};
	}
}

namespace TDP
{
	namespace Rendering
	{
		inline bool GLRenderDevice::StartedOK() const
		{
			return _startedOK;
		}
	}
}

#endif

